/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "PCR_Event_fp.h"

#if CC_PCR_Event  // Conditional expansion of this file

/*(See part 3 specification)
// Update PCR
*/
//  Return Type: TPM_RC
//      TPM_RC_LOCALITY             current command locality is not allowed to
//                                  extend the PCR referenced by 'pcrHandle'
/*
This command is used to cause an update to the indicated PCR.
The data in eventData is hashed using the hash algorithm associated with each bank in which the indicated PCR has been allocated. 
After the data is hashed, the digests list is returned.
 If the pcrHandle references an implemented PCR and not TPM_RH_NULL, the digests list is processed as in TPM2_PCR_Extend().
A TPM shall support an Event.size of zero through 1,024 inclusive (Event.size is an octet count). An Event.size of zero indicates 
that there is no data but the indicated operations will still occur,
EXAMPLE 1 If the command implements PCR[2] in a SHA1 bank and a SHA256 bank, then an extend to PCR[2] will cause eventData to be 
hashed twice, once with SHA1 and once with SHA256. The SHA1 hash of eventData will be Extended to PCR[2] in the SHA1 bank and the 
SHA256 hash of eventData will be Extended to PCR[2] of the SHA256 bank.
On successful command completion, digests will contain the list of tagged digests of eventData that was computed in preparation for 
extending the data into the PCR. 
At the option of the TPM, the list may contain a digest for each bank, or it may only contain a digest for each bank in which pcrHandle
 is extant.
If pcrHandle is TPM_RH_NULL, the TPM may return either an empty list or a digest for each bank.
EXAMPLE 2 Assume a TPM that implements a SHA1 bank and a SHA256 bank and that PCR[22] is only implemented in the SHA1 bank. If pcrHandle 
references PCR[22], then digests may contain either a SHA1 and a SHA256 digest or just a SHA1 digest

该命令用于引起对指示的 PCR 的更新。
eventData 中的数据使用与已分配指定 PCR 的每个银行关联的哈希算法进行哈希处理。 对数据进行哈希处理后，将返回摘要列表。
  如果 pcrHandle 引用已实现的 PCR 而不是 TPM_RH_NULL，则摘要列表将按照 TPM2_PCR_Extend() 中的方式进行处理。
TPM 应支持从零到 1,024 的 Event.size（Event.size 是一个八位字节数）。 Event.size 为零表示没有数据，但指示的操作仍会发生，
示例 1 如果命令在 SHA1 库和 SHA256 库中实施 PCR[2]，则对 PCR[2] 的扩展将导致 eventData 被散列两次，一次使用 SHA1，一次使用 SHA256。 
eventData 的 SHA1 散列将扩展到 SHA1 bank 中的 PCR[2]，eventData 的 SHA256 hash 将扩展到 SHA256 bank 中的 PCR[2]。
命令成功完成后，摘要将包含 eventData 的标记摘要列表，这些摘要是为将数据扩展到 PCR 中而计算的。
根据 TPM 的选择，该列表可能包含每个银行的摘要，或者它可能只包含 pcrHandle 存在的每个银行的摘要。
如果 pcrHandle 是 TPM_RH_NULL，TPM 可能会返回一个空列表或每个银行的摘要。
示例 2 假设 TPM 实现了 SHA1 库和 SHA256 库，并且 PCR[22] 仅在 SHA1 库中实现。 如果 pcrHandle 引用 PCR[22]，则摘要可能包含 SHA1
 和 SHA256 摘要或仅包含 SHA1 摘要
*/
TPM_RC
TPM2_PCR_Event(
    PCR_Event_In    *in,            // IN: input parameter list
    PCR_Event_Out   *out            // OUT: output parameter list
    )
{
    HASH_STATE          hashState;
    UINT32              i;
    UINT16              size;

// Input Validation

    // If a PCR extend is required
    if(in->pcrHandle != TPM_RH_NULL)
    {
        // If the PCR is not allow to extend, return error
        if(!PCRIsExtendAllowed(in->pcrHandle))
            return TPM_RC_LOCALITY;

        // If PCR is state saved and we need to update orderlyState, check NV
        // availability
        if(PCRIsStateSaved(in->pcrHandle))
            RETURN_IF_ORDERLY; 
    }

// Internal Data Update

    out->digests.count = HASH_COUNT;

    // Iterate supported PCR bank algorithms to extend
    for(i = 0; i < HASH_COUNT; i++)
    {
        TPM_ALG_ID  hash = CryptHashGetAlgByIndex(i);
        out->digests.digests[i].hashAlg = hash;
        size = CryptHashStart(&hashState, hash);
        CryptDigestUpdate2B(&hashState, &in->eventData.b);
        CryptHashEnd(&hashState, size,
                     (BYTE *)&out->digests.digests[i].digest);
        if(in->pcrHandle != TPM_RH_NULL)
            PCRExtend(in->pcrHandle, hash, size,
                      (BYTE *)&out->digests.digests[i].digest);
    }

    return TPM_RC_SUCCESS;
}

#endif // CC_PCR_Event